<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=2"><meta name="theme-color" content="#222"><meta name="generator" content="Hexo 5.4.0"><link rel="apple-touch-icon" sizes="180x180" href="/hexoblog/images/apple-touch-icon-next.png"><link rel="icon" type="image/png" sizes="32x32" href="/hexoblog/images/favicon-32x32-next.png"><link rel="icon" type="image/png" sizes="16x16" href="/hexoblog/images/favicon-16x16-next.png"><link rel="mask-icon" href="/hexoblog/images/logo.svg" color="#222"><link rel="stylesheet" href="/hexoblog/css/main.css"><link rel="stylesheet" href="https://unpkg.com/@fortawesome/fontawesome-free@5.15.3/css/all.min.css"><link rel="stylesheet" href="https://unpkg.com/animate.css@3.1.1/animate.min.css"><link rel="stylesheet" href="https://unpkg.com/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css"><script class="hexo-configurations">var NexT=window.NexT||{},CONFIG={hostname:"linqiankun.github.io",root:"/hexoblog/",images:"/hexoblog/images",scheme:"Gemini",version:"8.3.0",exturl:!1,sidebar:{position:"left",display:"post",padding:18,offset:12},copycode:!0,bookmark:{enable:!0,color:"#222",save:"auto"},fancybox:!0,mediumzoom:!1,lazyload:!1,pangu:!0,comments:{style:"tabs",active:null,storage:!0,lazyload:!1,nav:null},motion:{enable:!0,async:!1,transition:{post_block:"fadeIn",post_header:"fadeInDown",post_body:"fadeInDown",coll_header:"fadeInLeft",sidebar:"fadeInUp"}},prism:!1,i18n:{placeholder:"搜索...",empty:"没有找到任何搜索结果：${query}",hits_time:"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）",hits:"找到 ${hits} 个搜索结果"},path:"/hexoblog/search.xml",localsearch:{enable:!0,trigger:"auto",top_n_per_article:1,unescape:!1,preload:!1}}</script><meta name="description" content="服务启动暴露过程服务提供者暴露一个服务的详细过程"><meta property="og:type" content="article"><meta property="og:title" content="dubbo服务启动暴露过程"><meta property="og:url" content="https://linqiankun.github.io/hexoblog/md/rpc/dubbo/dubbo%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%9A%B4%E9%9C%B2%E8%BF%87%E7%A8%8B/index.html"><meta property="og:site_name" content="Study"><meta property="og:description" content="服务启动暴露过程服务提供者暴露一个服务的详细过程"><meta property="og:locale" content="zh_CN"><meta property="og:image" content="https://hexoimage.oss-cn-hangzhou.aliyuncs.com/hexobolg/java/dubbo-export.jpg"><meta property="article:published_time" content="2021-04-21T10:44:34.000Z"><meta property="article:modified_time" content="2024-05-14T07:26:15.421Z"><meta property="article:author" content="九分石人"><meta property="article:tag" content="dubbo"><meta property="article:tag" content="rpc"><meta name="twitter:card" content="summary"><meta name="twitter:image" content="https://hexoimage.oss-cn-hangzhou.aliyuncs.com/hexobolg/java/dubbo-export.jpg"><link rel="canonical" href="https://linqiankun.github.io/hexoblog/md/rpc/dubbo/dubbo%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%9A%B4%E9%9C%B2%E8%BF%87%E7%A8%8B/"><script class="page-configurations">CONFIG.page={sidebar:"",isHome:!1,isPost:!0,lang:"zh-CN"}</script><title>dubbo服务启动暴露过程 | Study</title><noscript><style>body{margin-top:2rem}.use-motion .collection-header,.use-motion .comments,.use-motion .menu-item,.use-motion .pagination,.use-motion .post-block,.use-motion .post-body,.use-motion .post-header,.use-motion .sidebar{visibility:visible}.use-motion .footer,.use-motion .header,.use-motion .site-brand-container .toggle{opacity:initial}.use-motion .custom-logo-image,.use-motion .site-subtitle,.use-motion .site-title{opacity:initial;top:initial}.use-motion .logo-line{transform:scaleX(1)}.search-pop-overlay,.sidebar-nav{display:none}.sidebar-panel{display:block}</style></noscript><link rel="alternate" href="/hexoblog/atom.xml" title="Study" type="application/atom+xml"><style>.darkmode--activated{--body-bg-color:#282828;--content-bg-color:#333;--card-bg-color:#555;--text-color:#ccc;--blockquote-color:#bbb;--link-color:#ccc;--link-hover-color:#eee;--brand-color:#ddd;--brand-hover-color:#ddd;--table-row-odd-bg-color:#282828;--table-row-hover-bg-color:#363636;--menu-item-bg-color:#555;--btn-default-bg:#222;--btn-default-color:#ccc;--btn-default-border-color:#555;--btn-default-hover-bg:#666;--btn-default-hover-color:#ccc;--btn-default-hover-border-color:#666;--highlight-background:#282b2e;--highlight-foreground:#a9b7c6;--highlight-gutter-background:#34393d;--highlight-gutter-foreground:#9ca9b6}.darkmode--activated img{opacity:.75}.darkmode--activated img:hover{opacity:.9}.darkmode--activated code{color:#69dbdc;background:0 0}button.darkmode-toggle{z-index:9999}.darkmode-ignore,img{display:flex!important}.beian img{display:inline-block!important}</style></head><body itemscope itemtype="http://schema.org/WebPage" class="use-motion"><div class="headband"></div><main class="main"><header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="header-inner"><div class="site-brand-container"><div class="site-nav-toggle"><div class="toggle" aria-label="切换导航栏" role="button"><span class="toggle-line"></span> <span class="toggle-line"></span> <span class="toggle-line"></span></div></div><div class="site-meta"><a href="/hexoblog/" class="brand" rel="start"><i class="logo-line"></i><h1 class="site-title">Study</h1><i class="logo-line"></i></a><p class="site-subtitle" itemprop="description">好好学习，天天向上！</p></div><div class="site-nav-right"><div class="toggle popup-trigger"><i class="fa fa-search fa-fw fa-lg"></i></div></div></div><nav class="site-nav"><ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/hexoblog/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/hexoblog/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/hexoblog/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/hexoblog/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/hexoblog/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li><li class="menu-item menu-item-sitemap"><a href="/hexoblog/sitemap.xml" rel="section"><i class="fa fa-sitemap fa-fw"></i>站点地图</a></li><li class="menu-item menu-item-search"><a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索</a></li></ul></nav><div class="search-pop-overlay"><div class="popup search-popup"><div class="search-header"><span class="search-icon"><i class="fa fa-search"></i></span><div class="search-input-container"><input autocomplete="off" autocapitalize="off" maxlength="80" placeholder="搜索..." spellcheck="false" type="search" class="search-input"></div><span class="popup-btn-close" role="button"><i class="fa fa-times-circle"></i></span></div><div class="search-result-container no-result"><div class="search-result-icon"><i class="fa fa-spinner fa-pulse fa-5x"></i></div></div></div></div></div><div class="toggle sidebar-toggle" role="button"><span class="toggle-line"></span> <span class="toggle-line"></span> <span class="toggle-line"></span></div><aside class="sidebar"><div class="sidebar-inner sidebar-nav-active sidebar-toc-active"><ul class="sidebar-nav"><li class="sidebar-nav-toc">文章目录</li><li class="sidebar-nav-overview">站点概览</li></ul><div class="sidebar-panel-container"><div class="post-toc-wrap sidebar-panel"><div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%9A%B4%E9%9C%B2%E8%BF%87%E7%A8%8B"><span class="nav-number">1.</span> <span class="nav-text">服务启动暴露过程</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%9C%8D%E5%8A%A1%E6%9A%B4%E9%9C%B2%E6%97%B6%E5%BA%8F%E5%9B%BE"><span class="nav-number">1.1.</span> <span class="nav-text">服务暴露时序图</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%87%E7%AD%BE%E7%9A%84%E8%A7%A3%E6%9E%90"><span class="nav-number">1.2.</span> <span class="nav-text">自定义标签的解析</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%8E%E6%9A%B4%E9%9C%B2"><span class="nav-number">1.3.</span> <span class="nav-text">服务注册与暴露</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%9C%AC%E5%9C%B0%E6%9A%B4%E9%9C%B2"><span class="nav-number">1.3.1.</span> <span class="nav-text">本地暴露</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%BF%9C%E7%A8%8B%E6%9A%B4%E9%9C%B2"><span class="nav-number">1.3.2.</span> <span class="nav-text">远程暴露</span></a></li></ol></li></ol></li></ol></div></div><div class="site-overview-wrap sidebar-panel"><div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person"><img class="site-author-image" itemprop="image" alt="九分石人" src="/hexoblog/images/avatar.png"><p class="site-author-name" itemprop="name">九分石人</p><div class="site-description" itemprop="description">my blogs</div></div><div class="site-state-wrap site-overview-item animated"><nav class="site-state"><div class="site-state-item site-state-posts"><a href="/hexoblog/archives/"><span class="site-state-item-count">239</span> <span class="site-state-item-name">日志</span></a></div><div class="site-state-item site-state-categories"><a href="/hexoblog/categories/"><span class="site-state-item-count">35</span> <span class="site-state-item-name">分类</span></a></div><div class="site-state-item site-state-tags"><a href="/hexoblog/tags/"><span class="site-state-item-count">64</span> <span class="site-state-item-name">标签</span></a></div></nav></div><div class="links-of-author site-overview-item animated"><span class="links-of-author-item"><a href="https://github.com/linqiankun" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;linqiankun" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a> </span><span class="links-of-author-item"><a href="linqiankun:191580378@qq.com" title="E-Mail → linqiankun:191580378@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a> </span><span class="links-of-author-item"><a href="https://weibo.com/jiufenshiren" title="Weibo → https:&#x2F;&#x2F;weibo.com&#x2F;jiufenshiren" rel="noopener" target="_blank"><i class="fab fa-weibo fa-fw"></i>Weibo</a> </span><span class="links-of-author-item"><a href="/hexoblog/atom.xml" title="Rss → &#x2F;atom.xml"><i class="fa fa-rss fa-fw"></i>Rss</a></span></div><div class="cc-license site-overview-item animated" itemprop="license"><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh-CN" class="cc-opacity" rel="noopener" target="_blank"><img src="/hexoblog/images/cc-by-nc-sa.svg" alt="Creative Commons"></a></div><div class="links-of-blogroll site-overview-item animated"><div class="links-of-blogroll-title"><i class="fa fa-globe fa-fw"></i> Links</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"><a href="http://124.222.164.140:3001/workspace/hexoblog" title="http:&#x2F;&#x2F;124.222.164.140:3001&#x2F;workspace&#x2F;hexoblog" rel="noopener" target="_blank">AnythingLLM</a></li><li class="links-of-blogroll-item"><a href="https://www.yuque.com/jiufenshiren" title="https:&#x2F;&#x2F;www.yuque.com&#x2F;jiufenshiren" rel="noopener" target="_blank">YuQue</a></li><li class="links-of-blogroll-item"><a href="https://github.com/LinQiankun" title="https:&#x2F;&#x2F;github.com&#x2F;LinQiankun" rel="noopener" target="_blank">Github</a></li><li class="links-of-blogroll-item"><a href="https://gitee.com/linqiankun" title="https:&#x2F;&#x2F;gitee.com&#x2F;linqiankun" rel="noopener" target="_blank">Gitee</a></li><li class="links-of-blogroll-item"><a href="https://my.oschina.net/linqiankun" title="https:&#x2F;&#x2F;my.oschina.net&#x2F;linqiankun" rel="noopener" target="_blank">OsChina</a></li><li class="links-of-blogroll-item"><a href="https://segmentfault.com/u/jiufenshiren" title="https:&#x2F;&#x2F;segmentfault.com&#x2F;u&#x2F;jiufenshiren" rel="noopener" target="_blank">Segmentfault</a></li><li class="links-of-blogroll-item"><a href="https://juejin.cn/user/3263006243306205" title="https:&#x2F;&#x2F;juejin.cn&#x2F;user&#x2F;3263006243306205" rel="noopener" target="_blank">Juejin</a></li><li class="links-of-blogroll-item"><a href="https://blog.csdn.net/qq_36985536?spm=1010.2135.3001.5421" title="https:&#x2F;&#x2F;blog.csdn.net&#x2F;qq_36985536?spm&#x3D;1010.2135.3001.5421" rel="noopener" target="_blank">CSDN</a></li><li class="links-of-blogroll-item"><a href="https://www.cnblogs.com/jiufenshiren" title="https:&#x2F;&#x2F;www.cnblogs.com&#x2F;jiufenshiren" rel="noopener" target="_blank">CnBlogs</a></li><li class="links-of-blogroll-item"><a href="https://home.51cto.com/space?uid=12848310" title="https:&#x2F;&#x2F;home.51cto.com&#x2F;space?uid&#x3D;12848310" rel="noopener" target="_blank">51CTO</a></li></ul></div><script data-embed-id="94f790d6-f7ac-4d04-ad53-55d841525b5a" data-base-api-url="http://124.222.164.140:3001/api/embed" src="http://124.222.164.140:3001/embed/anythingllm-chat-widget.min.js"></script></div></div></div></aside><div class="sidebar-dimmer"></div></header><div class="back-to-top" role="button" aria-label="返回顶部"><i class="fa fa-arrow-up"></i> <span>0%</span></div><a role="button" class="book-mark-link book-mark-link-fixed"></a><noscript><div class="noscript-warning">Theme NexT works best with JavaScript enabled</div></noscript><div class="main-inner post posts-expand"><div class="post-block"><article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN"><link itemprop="mainEntityOfPage" href="https://linqiankun.github.io/hexoblog/md/rpc/dubbo/dubbo%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%9A%B4%E9%9C%B2%E8%BF%87%E7%A8%8B/"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="image" content="/hexoblog/images/avatar.png"><meta itemprop="name" content="九分石人"><meta itemprop="description" content="my blogs"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Study"></span><header class="post-header"><h1 class="post-title" itemprop="name headline">dubbo服务启动暴露过程</h1><div class="post-meta-container"><div class="post-meta"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar"></i> </span><span class="post-meta-item-text">发表于</span> <time title="创建时间：2021-04-21 18:44:34 18:44:34" itemprop="dateCreated datePublished" datetime="2021-04-21T18:44:34+08:00">2021-04-21 18:44:34</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar-check"></i> </span><span class="post-meta-item-text">更新于</span> <time title="修改时间：2024-05-14 15:26:15 15:26:15" itemprop="dateModified" datetime="2024-05-14T15:26:15+08:00">2024-05-14 15:26:15</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-folder"></i> </span><span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/hexoblog/categories/rpc/" itemprop="url" rel="index"><span itemprop="name">rpc</span></a> </span>， <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/hexoblog/categories/rpc/dubbo/" itemprop="url" rel="index"><span itemprop="name">dubbo</span></a> </span></span><span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display:none"><span class="post-meta-item-icon"><i class="far fa-eye"></i> </span><span class="post-meta-item-text">阅读次数：</span> <span id="busuanzi_value_page_pv"></span></span></div><div class="post-meta"><span class="post-meta-item" title="本文字数"><span class="post-meta-item-icon"><i class="far fa-file-word"></i> </span><span class="post-meta-item-text">本文字数：</span> <span>24k</span> </span><span class="post-meta-item" title="阅读时长"><span class="post-meta-item-icon"><i class="far fa-clock"></i> </span><span class="post-meta-item-text">阅读时长 &asymp;</span> <span>22 分钟</span></span></div></div></header><div class="post-body" itemprop="articleBody"><h1 id="服务启动暴露过程"><a href="#服务启动暴露过程" class="headerlink" title="服务启动暴露过程"></a>服务启动暴露过程</h1><p><a target="_blank" rel="noopener" href="https://dubbo.apache.org/zh/docs/v2.7/dev/implementation/#%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%9A%B4%E9%9C%B2%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E7%9A%84%E8%AF%A6%E7%BB%86%E8%BF%87%E7%A8%8B">服务提供者暴露一个服务的详细过程</a></p><span id="more"></span><h2 id="服务暴露时序图"><a href="#服务暴露时序图" class="headerlink" title="服务暴露时序图"></a>服务暴露时序图</h2><p><img src="https://hexoimage.oss-cn-hangzhou.aliyuncs.com/hexobolg/java/dubbo-export.jpg" alt="暴露时序图"></p><h2 id="自定义标签的解析"><a href="#自定义标签的解析" class="headerlink" title="自定义标签的解析"></a>自定义标签的解析</h2><p>&emsp;&emsp;通常在项目启动的过程中，我们会将dubbo的配置文件写入spring的配置文件中。</p><p><a target="_blank" rel="noopener" href="https://dubbo.apache.org/zh/docs/v2.7/dev/implementation/#%E8%A7%A3%E6%9E%90%E6%9C%8D%E5%8A%A1">解析服务</a></p><blockquote><p>&emsp;&emsp;基于 dubbo.jar 内的 META-INF/spring.handlers 配置，Spring 在遇到 dubbo 名称空间时，会回调 DubboNamespaceHandler。<br>&emsp;&emsp;所有 dubbo 的标签，都统一用 DubboBeanDefinitionParser 进行解析，基于一对一属性映射，将 XML 标签解析为 Bean 对象。</p></blockquote><p>&emsp;&emsp;根据官方文档，在spring启动过程中，碰到dubbo开头的标签，会由<code>DubboNamespaceHandler</code>处理。这里也是基于spring自定义标签，的扩展机制。</p><p>&emsp;&emsp;META-INF/spring.schemas文件。定义dubbo.xml文件格式，约束。</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">http\:<span class="regexp">//</span>dubbo.apache.org<span class="regexp">/schema/</span>dubbo<span class="regexp">/dubbo.xsd=META-INF/</span>dubbo.xsd</span><br><span class="line">http\:<span class="regexp">//</span>code.alibabatech.com<span class="regexp">/schema/</span>dubbo<span class="regexp">/dubbo.xsd=META-INF/</span>compat/dubbo.xsd</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;META-INF/spring.handlers文件，定义了xml文件的命名空间处理器，负责解析dubbo.xml。</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">http\:<span class="regexp">//</span>dubbo.apache.org<span class="regexp">/schema/</span>dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler</span><br><span class="line">http\:<span class="regexp">//</span>code.alibabatech.com<span class="regexp">/schema/</span>dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;命名空间处理器。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DubboNamespaceHandler</span> <span class="keyword">extends</span> <span class="title">NamespaceHandlerSupport</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        Version.checkDuplicate(DubboNamespaceHandler.class);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;application&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(ApplicationConfig.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;module&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(ModuleConfig.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;registry&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(RegistryConfig.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;config-center&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(ConfigCenterBean.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;metadata-report&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(MetadataReportConfig.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;monitor&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(MonitorConfig.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;provider&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(ProviderConfig.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;consumer&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(ConsumerConfig.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;protocol&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(ProtocolConfig.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;service&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(ServiceBean.class, <span class="keyword">true</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;reference&quot;</span>, <span class="keyword">new</span> DubboBeanDefinitionParser(ReferenceBean.class, <span class="keyword">false</span>));</span><br><span class="line">        registerBeanDefinitionParser(<span class="string">&quot;annotation&quot;</span>, <span class="keyword">new</span> AnnotationBeanDefinitionParser());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;遇到不同的标签会交由不同的处理器（Parser）进行处理。</p><h2 id="服务注册与暴露"><a href="#服务注册与暴露" class="headerlink" title="服务注册与暴露"></a>服务注册与暴露</h2><p><a target="_blank" rel="noopener" href="https://dubbo.apache.org/zh/docs/v2.7/dev/implementation/#%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1">暴露服务</a></p><blockquote><p>&emsp;&emsp;在 ServiceConfig.export() 或 ReferenceConfig.get() 初始化时，将 Bean 对象转换 URL 格式，所有 Bean 属性转成 URL 的参数。<br>&emsp;&emsp;然后将 URL 传给 协议扩展点，基于扩展点的 扩展点自适应机制，根据 URL 的协议头，进行不同协议的服务暴露或引用。</p></blockquote><p>&emsp;&emsp;基于上面解析的结果，会在spring容器中生成对应的ServiceBean实例，这个bean实现了很多方法，初始化，销毁等。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ServiceBean</span>&lt;<span class="title">T</span>&gt; <span class="keyword">extends</span> <span class="title">ServiceConfig</span>&lt;<span class="title">T</span>&gt; <span class="keyword">implements</span> <span class="title">InitializingBean</span>, <span class="title">DisposableBean</span>,</span></span><br><span class="line"><span class="class">        <span class="title">ApplicationContextAware</span>, <span class="title">ApplicationListener</span>&lt;<span class="title">ContextRefreshedEvent</span>&gt;, <span class="title">BeanNameAware</span>,</span></span><br><span class="line"><span class="class">        <span class="title">ApplicationEventPublisherAware</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;而在spring初始化完成bean的组装后会调用InitializingBean的afterPropertiesSet方法。<br>&emsp;&emsp;在spring容器完成加载，会接收到ContextRefreshedEvent事件，调用ApplicationListener的onApplicationEvent方法。<br>&emsp;&emsp;这两个方法中会调用export方法，间接调用ServiceConfig中的export方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="meta">@SuppressWarnings(&#123;&quot;unchecked&quot;, &quot;deprecation&quot;&#125;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">    ···</span><br><span class="line">    <span class="comment">// 省略一堆流程</span></span><br><span class="line">    <span class="keyword">if</span> (!supportedApplicationListener) &#123;</span><br><span class="line">        export();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onApplicationEvent</span><span class="params">(ContextRefreshedEvent event)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (!isExported() &amp;&amp; !isUnexported()) &#123;</span><br><span class="line">        <span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">            logger.info(<span class="string">&quot;The service ready on spring started. service: &quot;</span> + getInterface());</span><br><span class="line">        &#125;</span><br><span class="line">        export();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;ServiceConfig的export方法中。调用了本地的doExport方法。在这里如果发现有延迟属性（delay），则延迟时间暴露服务，如果没有就直接暴露服务。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">export</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    checkAndUpdateSubConfigs();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!shouldExport()) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (shouldDelay()) &#123;</span><br><span class="line">        delayExportExecutor.schedule(<span class="keyword">this</span>::doExport, delay, TimeUnit.MILLISECONDS);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        doExport();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;ServiceConfig的doExport方法中。调用了本地的doExportUrls方法，紧接着就调用了doExportUrlsFor1Protocol方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">doExport</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (unexported) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">&quot;The service &quot;</span> + interfaceClass.getName() + <span class="string">&quot; has already unexported!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (exported) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    exported = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (StringUtils.isEmpty(path)) &#123;</span><br><span class="line">        path = interfaceName;</span><br><span class="line">    &#125;</span><br><span class="line">    doExportUrls();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doExportUrls</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    List&lt;URL&gt; registryURLs = loadRegistries(<span class="keyword">true</span>);</span><br><span class="line">    <span class="keyword">for</span> (ProtocolConfig protocolConfig : protocols) &#123;</span><br><span class="line">        String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -&gt; p + <span class="string">&quot;/&quot;</span> + path).orElse(path), group, version);</span><br><span class="line">        ProviderModel providerModel = <span class="keyword">new</span> ProviderModel(pathKey, ref, interfaceClass);</span><br><span class="line">        ApplicationModel.initProviderModel(pathKey, providerModel);</span><br><span class="line">        doExportUrlsFor1Protocol(protocolConfig, registryURLs);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;在doExportUrls中，按照不同的Protocol暴露服务，在不同的zookeeper上集群上注册自己的服务。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doExportUrlsFor1Protocol</span><span class="params">(ProtocolConfig protocolConfig, List&lt;URL&gt; registryURLs)</span> </span>&#123;</span><br><span class="line">    String name = protocolConfig.getName();</span><br><span class="line">    <span class="keyword">if</span> (StringUtils.isEmpty(name)) &#123;</span><br><span class="line">        name = Constants.DUBBO;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Map&lt;String, String&gt; map = <span class="keyword">new</span> HashMap&lt;String, String&gt;();</span><br><span class="line">    map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);</span><br><span class="line">    appendRuntimeParameters(map);</span><br><span class="line">    appendParameters(map, application);</span><br><span class="line">    appendParameters(map, <span class="keyword">module</span>);</span><br><span class="line">    appendParameters(map, provider, Constants.DEFAULT_KEY);</span><br><span class="line">    appendParameters(map, protocolConfig);</span><br><span class="line">    appendParameters(map, <span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">if</span> (CollectionUtils.isNotEmpty(methods)) &#123;</span><br><span class="line">        <span class="keyword">for</span> (MethodConfig method : methods) &#123;</span><br><span class="line">            appendParameters(map, method, method.getName());</span><br><span class="line">            String retryKey = method.getName() + <span class="string">&quot;.retry&quot;</span>;</span><br><span class="line">            <span class="keyword">if</span> (map.containsKey(retryKey)) &#123;</span><br><span class="line">                String retryValue = map.remove(retryKey);</span><br><span class="line">                <span class="keyword">if</span> (<span class="string">&quot;false&quot;</span>.equals(retryValue)) &#123;</span><br><span class="line">                    map.put(method.getName() + <span class="string">&quot;.retries&quot;</span>, <span class="string">&quot;0&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            List&lt;ArgumentConfig&gt; arguments = method.getArguments();</span><br><span class="line">            <span class="keyword">if</span> (CollectionUtils.isNotEmpty(arguments)) &#123;</span><br><span class="line">                <span class="keyword">for</span> (ArgumentConfig argument : arguments) &#123;</span><br><span class="line">                    <span class="comment">// convert argument type</span></span><br><span class="line">                    <span class="keyword">if</span> (argument.getType() != <span class="keyword">null</span> &amp;&amp; argument.getType().length() &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                        Method[] methods = interfaceClass.getMethods();</span><br><span class="line">                        <span class="comment">// visit all methods</span></span><br><span class="line">                        <span class="keyword">if</span> (methods != <span class="keyword">null</span> &amp;&amp; methods.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; methods.length; i++) &#123;</span><br><span class="line">                                String methodName = methods[i].getName();</span><br><span class="line">                                <span class="comment">// target the method, and get its signature</span></span><br><span class="line">                                <span class="keyword">if</span> (methodName.equals(method.getName())) &#123;</span><br><span class="line">                                    Class&lt;?&gt;[] argtypes = methods[i].getParameterTypes();</span><br><span class="line">                                    <span class="comment">// one callback in the method</span></span><br><span class="line">                                    <span class="keyword">if</span> (argument.getIndex() != -<span class="number">1</span>) &#123;</span><br><span class="line">                                        <span class="keyword">if</span> (argtypes[argument.getIndex()].getName().equals(argument.getType())) &#123;</span><br><span class="line">                                            appendParameters(map, argument, method.getName() + <span class="string">&quot;.&quot;</span> + argument.getIndex());</span><br><span class="line">                                        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                                            <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Argument config error : the index attribute and type attribute not match :index :&quot;</span> + argument.getIndex() + <span class="string">&quot;, type:&quot;</span> + argument.getType());</span><br><span class="line">                                        &#125;</span><br><span class="line">                                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                                        <span class="comment">// multiple callbacks in the method</span></span><br><span class="line">                                        <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; argtypes.length; j++) &#123;</span><br><span class="line">                                            Class&lt;?&gt; argclazz = argtypes[j];</span><br><span class="line">                                            <span class="keyword">if</span> (argclazz.getName().equals(argument.getType())) &#123;</span><br><span class="line">                                                appendParameters(map, argument, method.getName() + <span class="string">&quot;.&quot;</span> + j);</span><br><span class="line">                                                <span class="keyword">if</span> (argument.getIndex() != -<span class="number">1</span> &amp;&amp; argument.getIndex() != j) &#123;</span><br><span class="line">                                                    <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Argument config error : the index attribute and type attribute not match :index :&quot;</span> + argument.getIndex() + <span class="string">&quot;, type:&quot;</span> + argument.getType());</span><br><span class="line">                                                &#125;</span><br><span class="line">                                            &#125;</span><br><span class="line">                                        &#125;</span><br><span class="line">                                    &#125;</span><br><span class="line">                                &#125;</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (argument.getIndex() != -<span class="number">1</span>) &#123;</span><br><span class="line">                        appendParameters(map, argument, method.getName() + <span class="string">&quot;.&quot;</span> + argument.getIndex());</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Argument config must set index or type attribute.eg: &lt;dubbo:argument index=&#x27;0&#x27; .../&gt; or &lt;dubbo:argument type=xxx .../&gt;&quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="comment">// end of methods for</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (ProtocolUtils.isGeneric(generic)) &#123;</span><br><span class="line">        map.put(Constants.GENERIC_KEY, generic);</span><br><span class="line">        map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        String revision = Version.getVersion(interfaceClass, version);</span><br><span class="line">        <span class="keyword">if</span> (revision != <span class="keyword">null</span> &amp;&amp; revision.length() &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            map.put(<span class="string">&quot;revision&quot;</span>, revision);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();</span><br><span class="line">        <span class="keyword">if</span> (methods.length == <span class="number">0</span>) &#123;</span><br><span class="line">            logger.warn(<span class="string">&quot;No method found in service interface &quot;</span> + interfaceClass.getName());</span><br><span class="line">            map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            map.put(Constants.METHODS_KEY, StringUtils.join(<span class="keyword">new</span> HashSet&lt;String&gt;(Arrays.asList(methods)), <span class="string">&quot;,&quot;</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (!ConfigUtils.isEmpty(token)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (ConfigUtils.isDefault(token)) &#123;</span><br><span class="line">            map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString());</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            map.put(Constants.TOKEN_KEY, token);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// export service</span></span><br><span class="line">    String host = <span class="keyword">this</span>.findConfigedHosts(protocolConfig, registryURLs, map);</span><br><span class="line">    Integer port = <span class="keyword">this</span>.findConfigedPorts(protocolConfig, name, map);</span><br><span class="line">    URL url = <span class="keyword">new</span> URL(name, host, port, getContextPath(protocolConfig).map(p -&gt; p + <span class="string">&quot;/&quot;</span> + path).orElse(path), map);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)</span><br><span class="line">            .hasExtension(url.getProtocol())) &#123;</span><br><span class="line">        url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)</span><br><span class="line">                .getExtension(url.getProtocol()).getConfigurator(url).configure(url);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    String scope = url.getParameter(Constants.SCOPE_KEY);</span><br><span class="line">    <span class="comment">// don&#x27;t export when none is configured</span></span><br><span class="line">    <span class="keyword">if</span> (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// export to local if the config is not remote (export to remote only when config is remote)</span></span><br><span class="line">        <span class="keyword">if</span> (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) &#123;</span><br><span class="line">            exportLocal(url);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// export to remote if the config is not local (export to local only when config is local)</span></span><br><span class="line">        <span class="keyword">if</span> (!Constants.SCOPE_LOCAL.equalsIgnoreCase(scope)) &#123;</span><br><span class="line">            <span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">                logger.info(<span class="string">&quot;Export dubbo service &quot;</span> + interfaceClass.getName() + <span class="string">&quot; to url &quot;</span> + url);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (CollectionUtils.isNotEmpty(registryURLs)) &#123;</span><br><span class="line">                <span class="keyword">for</span> (URL registryURL : registryURLs) &#123;</span><br><span class="line">                    url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));</span><br><span class="line">                    URL monitorUrl = loadMonitor(registryURL);</span><br><span class="line">                    <span class="keyword">if</span> (monitorUrl != <span class="keyword">null</span>) &#123;</span><br><span class="line">                        url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">if</span> (logger.isInfoEnabled()) &#123;</span><br><span class="line">                        logger.info(<span class="string">&quot;Register dubbo service &quot;</span> + interfaceClass.getName() + <span class="string">&quot; url &quot;</span> + url + <span class="string">&quot; to registry &quot;</span> + registryURL);</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                    <span class="comment">// For providers, this is used to enable custom proxy to generate invoker</span></span><br><span class="line">                    String proxy = url.getParameter(Constants.PROXY_KEY);</span><br><span class="line">                    <span class="keyword">if</span> (StringUtils.isNotEmpty(proxy)) &#123;</span><br><span class="line">                        registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                    Invoker&lt;?&gt; invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));</span><br><span class="line">                    DelegateProviderMetaDataInvoker wrapperInvoker = <span class="keyword">new</span> DelegateProviderMetaDataInvoker(invoker, <span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">                    Exporter&lt;?&gt; exporter = protocol.export(wrapperInvoker);</span><br><span class="line">                    exporters.add(exporter);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                Invoker&lt;?&gt; invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);</span><br><span class="line">                DelegateProviderMetaDataInvoker wrapperInvoker = <span class="keyword">new</span> DelegateProviderMetaDataInvoker(invoker, <span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">                Exporter&lt;?&gt; exporter = protocol.export(wrapperInvoker);</span><br><span class="line">                exporters.add(exporter);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">/**</span></span><br><span class="line"><span class="comment">                * <span class="doctag">@since</span> 2.7.0</span></span><br><span class="line"><span class="comment">                * ServiceData Store</span></span><br><span class="line"><span class="comment">                */</span></span><br><span class="line">            MetadataReportService metadataReportService = <span class="keyword">null</span>;</span><br><span class="line">            <span class="keyword">if</span> ((metadataReportService = getMetadataReportService()) != <span class="keyword">null</span>) &#123;</span><br><span class="line">                metadataReportService.publishProvider(url);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">this</span>.urls.add(url);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;这里采用一个map保存下来所有的url参数和value值，然后调用代理工厂根据ref（实际服务提供对象）获取invoker对象（接口的代理对象），在使用protocol转为exporter，将服务暴露出去。<br>&emsp;&emsp;代理工厂采用SPI机制来搞，可以选择代理方式。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();</span><br></pre></td></tr></table></figure><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">stub=org<span class="selector-class">.apache</span><span class="selector-class">.dubbo</span><span class="selector-class">.rpc</span><span class="selector-class">.proxy</span><span class="selector-class">.wrapper</span>.StubProxyFactoryWrapper</span><br><span class="line">jdk=org<span class="selector-class">.apache</span><span class="selector-class">.dubbo</span><span class="selector-class">.rpc</span><span class="selector-class">.proxy</span><span class="selector-class">.jdk</span>.JdkProxyFactory</span><br><span class="line">javassist=org<span class="selector-class">.apache</span><span class="selector-class">.dubbo</span><span class="selector-class">.rpc</span><span class="selector-class">.proxy</span><span class="selector-class">.javassist</span>.JavassistProxyFactory</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;这里使用了SPI机制去确定使用那个协议对应的protocol。这里采用了很多的SPI机制，自适应，自动包装。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();</span><br></pre></td></tr></table></figure><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">filter</span>=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper</span><br><span class="line"><span class="attribute">listener</span>=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper</span><br><span class="line"></span><br><span class="line"><span class="attribute">mock</span>=org.apache.dubbo.rpc.support.MockProtocol</span><br><span class="line"><span class="attribute">dubbo</span>=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol</span><br><span class="line"><span class="attribute">injvm</span>=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol</span><br><span class="line"><span class="attribute">rmi</span>=org.apache.dubbo.rpc.protocol.rmi.RmiProtocol</span><br><span class="line"><span class="attribute">hessian</span>=org.apache.dubbo.rpc.protocol.hessian.HessianProtocol</span><br><span class="line"><span class="attribute">http</span>=org.apache.dubbo.rpc.protocol.http.HttpProtocol</span><br><span class="line"></span><br><span class="line">org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol</span><br><span class="line"><span class="attribute">thrift</span>=org.apache.dubbo.rpc.protocol.thrift.ThriftProtocol</span><br><span class="line"><span class="attribute">memcached</span>=org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol</span><br><span class="line"><span class="attribute">redis</span>=org.apache.dubbo.rpc.protocol.redis.RedisProtocol</span><br><span class="line"><span class="attribute">rest</span>=org.apache.dubbo.rpc.protocol.rest.RestProtocol</span><br><span class="line"><span class="attribute">registry</span>=org.apache.dubbo.registry.integration.RegistryProtocol</span><br><span class="line"></span><br><span class="line"><span class="attribute">qos</span>=org.apache.dubbo.qos.protocol.QosProtocolWrapper</span><br></pre></td></tr></table></figure><h3 id="本地暴露"><a href="#本地暴露" class="headerlink" title="本地暴露"></a>本地暴露</h3><p><a target="_blank" rel="noopener" href="https://dubbo.apache.org/zh/docs/v2.7/dev/implementation/#1-%E5%8F%AA%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%A3">只暴露服务端口</a></p><p>&emsp;&emsp;当在本地暴露服务时，默认会进入DubboProtocol，也可以配置其他协议。在DubboProtocol中：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function">Exporter&lt;T&gt; <span class="title">export</span><span class="params">(Invoker&lt;T&gt; invoker)</span> <span class="keyword">throws</span> RpcException </span>&#123;</span><br><span class="line">    URL url = invoker.getUrl();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// export service.</span></span><br><span class="line">    String key = serviceKey(url);</span><br><span class="line">    DubboExporter&lt;T&gt; exporter = <span class="keyword">new</span> DubboExporter&lt;T&gt;(invoker, key, exporterMap);</span><br><span class="line">    exporterMap.put(key, exporter);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//export an stub service for dispatching event</span></span><br><span class="line">    Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);</span><br><span class="line">    Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, <span class="keyword">false</span>);</span><br><span class="line">    <span class="keyword">if</span> (isStubSupportEvent &amp;&amp; !isCallbackservice) &#123;</span><br><span class="line">        String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);</span><br><span class="line">        <span class="keyword">if</span> (stubServiceMethods == <span class="keyword">null</span> || stubServiceMethods.length() == <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (logger.isWarnEnabled()) &#123;</span><br><span class="line">                logger.warn(<span class="keyword">new</span> IllegalStateException(<span class="string">&quot;consumer [&quot;</span> + url.getParameter(Constants.INTERFACE_KEY) +</span><br><span class="line">                        <span class="string">&quot;], has set stubproxy support event ,but no stub methods founded.&quot;</span>));</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    openServer(url);</span><br><span class="line">    optimizeSerialization(url);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> exporter;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;export方法调用openServer方法开启服务，如果服务不存在就创建一个服务。这里默认是netty服务，也可以通过SPI使用其他的。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">openServer</span><span class="params">(URL url)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// find server.</span></span><br><span class="line">    String key = url.getAddress();</span><br><span class="line">    <span class="comment">//client can export a service which&#x27;s only for server to invoke</span></span><br><span class="line">    <span class="keyword">boolean</span> isServer = url.getParameter(Constants.IS_SERVER_KEY, <span class="keyword">true</span>);</span><br><span class="line">    <span class="keyword">if</span> (isServer) &#123;</span><br><span class="line">        ExchangeServer server = serverMap.get(key);</span><br><span class="line">        <span class="keyword">if</span> (server == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">synchronized</span> (<span class="keyword">this</span>) &#123;</span><br><span class="line">                server = serverMap.get(key);</span><br><span class="line">                <span class="keyword">if</span> (server == <span class="keyword">null</span>) &#123;</span><br><span class="line">                    serverMap.put(key, createServer(url));</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// server supports reset, use together with override</span></span><br><span class="line">            server.reset(url);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> ExchangeServer <span class="title">createServer</span><span class="params">(URL url)</span> </span>&#123;</span><br><span class="line">    url = URLBuilder.from(url)</span><br><span class="line">            <span class="comment">// send readonly event when server closes, it&#x27;s enabled by default</span></span><br><span class="line">            .addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())</span><br><span class="line">            <span class="comment">// enable heartbeat by default</span></span><br><span class="line">            .addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT))</span><br><span class="line">            .addParameter(Constants.CODEC_KEY, DubboCodec.NAME)</span><br><span class="line">            .build();</span><br><span class="line">    String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (str != <span class="keyword">null</span> &amp;&amp; str.length() &gt; <span class="number">0</span> &amp;&amp; !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> RpcException(<span class="string">&quot;Unsupported server type: &quot;</span> + str + <span class="string">&quot;, url: &quot;</span> + url);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ExchangeServer server;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        server = Exchangers.bind(url, requestHandler);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (RemotingException e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> RpcException(<span class="string">&quot;Fail to start server(url: &quot;</span> + url + <span class="string">&quot;) &quot;</span> + e.getMessage(), e);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    str = url.getParameter(Constants.CLIENT_KEY);</span><br><span class="line">    <span class="keyword">if</span> (str != <span class="keyword">null</span> &amp;&amp; str.length() &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        Set&lt;String&gt; supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();</span><br><span class="line">        <span class="keyword">if</span> (!supportedTypes.contains(str)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> RpcException(<span class="string">&quot;Unsupported client type: &quot;</span> + str);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> server;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;而在headerExchanger的bind中，调用了Transporters.bind()，一直调用到NettyServer,绑定了端口和链接。而消费的时候则是一直调用connect方法建立连接。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ExchangeServer <span class="title">bind</span><span class="params">(URL url, ExchangeHandler handler)</span> <span class="keyword">throws</span> RemotingException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (url == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;url == null&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (handler == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;handler == null&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    url = url.addParameterIfAbsent(Constants.CODEC_KEY, <span class="string">&quot;exchange&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> getExchanger(url).bind(url, handler);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取Exchanger，这里有SPI（基本使用）但是只有HeaderExchanger一个实现。</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Exchanger <span class="title">getExchanger</span><span class="params">(URL url)</span> </span>&#123;</span><br><span class="line">    String type = url.getParameter(Constants.EXCHANGER_KEY, Constants.DEFAULT_EXCHANGER);</span><br><span class="line">    <span class="keyword">return</span> getExchanger(type);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Exchanger <span class="title">getExchanger</span><span class="params">(String type)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SPI(HeaderExchanger.NAME)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Exchanger</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * bind.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> url</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> handler</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> message server</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Adaptive(&#123;Constants.EXCHANGER_KEY&#125;)</span></span><br><span class="line">    <span class="function">ExchangeServer <span class="title">bind</span><span class="params">(URL url, ExchangeHandler handler)</span> <span class="keyword">throws</span> RemotingException</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * connect.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> url</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> handler</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> message channel</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Adaptive(&#123;Constants.EXCHANGER_KEY&#125;)</span></span><br><span class="line">    <span class="function">ExchangeClient <span class="title">connect</span><span class="params">(URL url, ExchangeHandler handler)</span> <span class="keyword">throws</span> RemotingException</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;Exchanger只有HeaderExchanger一个实现类。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HeaderExchanger</span> <span class="keyword">implements</span> <span class="title">Exchanger</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String NAME = <span class="string">&quot;header&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ExchangeClient <span class="title">connect</span><span class="params">(URL url, ExchangeHandler handler)</span> <span class="keyword">throws</span> RemotingException </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> HeaderExchangeClient(Transporters.connect(url, <span class="keyword">new</span> DecodeHandler(<span class="keyword">new</span> HeaderExchangeHandler(handler))), <span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ExchangeServer <span class="title">bind</span><span class="params">(URL url, ExchangeHandler handler)</span> <span class="keyword">throws</span> RemotingException </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> HeaderExchangeServer(Transporters.bind(url, <span class="keyword">new</span> DecodeHandler(<span class="keyword">new</span> HeaderExchangeHandler(handler))));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;HeaderExchanger中调用了Transporters的bind方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Transporters</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Server <span class="title">bind</span><span class="params">(URL url, ChannelHandler... handlers)</span> <span class="keyword">throws</span> RemotingException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (url == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;url == null&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (handlers == <span class="keyword">null</span> || handlers.length == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;handlers == null&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    ChannelHandler handler;</span><br><span class="line">    <span class="keyword">if</span> (handlers.length == <span class="number">1</span>) &#123;</span><br><span class="line">        handler = handlers[<span class="number">0</span>];</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        handler = <span class="keyword">new</span> ChannelHandlerDispatcher(handlers);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> getTransporter().bind(url, handler);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Transporter <span class="title">getTransporter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;这里也采用SPI机制（扩展点自适应）选择使用的底层框架。默认是netty创建服务。</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">netty3=org.apache.dubbo.remoting.transport.netty.NettyTransporter</span><br><span class="line">netty4=org.apache.dubbo.remoting.transport.netty4.NettyTransporter</span><br><span class="line">netty=org.apache.dubbo.remoting.transport.netty4.NettyTransporter</span><br><span class="line">mina=org.apache.dubbo.remoting.transport.mina.MinaTransporter</span><br><span class="line">grizzly=org.apache.dubbo.remoting.transport.grizzly.GrizzlyTransporter</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SPI(&quot;netty&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Transporter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Bind a server.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> url     server url</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> handler</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> server</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> RemotingException</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@see</span> org.apache.dubbo.remoting.Transporters#bind(URL, ChannelHandler...)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Adaptive(&#123;Constants.SERVER_KEY, Constants.TRANSPORTER_KEY&#125;)</span></span><br><span class="line">    <span class="function">Server <span class="title">bind</span><span class="params">(URL url, ChannelHandler handler)</span> <span class="keyword">throws</span> RemotingException</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Connect to a server.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> url     server url</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> handler</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> client</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> RemotingException</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@see</span> org.apache.dubbo.remoting.Transporters#connect(URL, ChannelHandler...)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Adaptive(&#123;Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY&#125;)</span></span><br><span class="line">    <span class="function">Client <span class="title">connect</span><span class="params">(URL url, ChannelHandler handler)</span> <span class="keyword">throws</span> RemotingException</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NettyTransporter</span> <span class="keyword">implements</span> <span class="title">Transporter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String NAME = <span class="string">&quot;netty3&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Server <span class="title">bind</span><span class="params">(URL url, ChannelHandler listener)</span> <span class="keyword">throws</span> RemotingException </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> NettyServer(url, listener);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Client <span class="title">connect</span><span class="params">(URL url, ChannelHandler listener)</span> <span class="keyword">throws</span> RemotingException </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> NettyClient(url, listener);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="远程暴露"><a href="#远程暴露" class="headerlink" title="远程暴露"></a>远程暴露</h3><p><a target="_blank" rel="noopener" href="https://dubbo.apache.org/zh/docs/v2.7/dev/implementation/#2-%E5%90%91%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1">向注册中心暴露服务</a></p><p>&emsp;&emsp;这里有了在本地暴露的流程，远程暴露的流程呢？<br>&emsp;&emsp;在上面根据扩展点自动选择协议时，有扩展点自动包装的扩展类，ProtocolFilterWrapper，ProtocolListenerWrapper，QosProtocolWrapper。<br>&emsp;&emsp;在ProtocolFilterWrapper和ProtocolListenerWrapper中：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ProtocolFilterWrapper</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function">Exporter&lt;T&gt; <span class="title">export</span><span class="params">(Invoker&lt;T&gt; invoker)</span> <span class="keyword">throws</span> RpcException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) &#123;</span><br><span class="line">        <span class="keyword">return</span> protocol.export(invoker);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ProtocolListenerWrapper</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function">Exporter&lt;T&gt; <span class="title">export</span><span class="params">(Invoker&lt;T&gt; invoker)</span> <span class="keyword">throws</span> RpcException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) &#123;</span><br><span class="line">        <span class="keyword">return</span> protocol.export(invoker);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ListenerExporterWrapper&lt;T&gt;(protocol.export(invoker),</span><br><span class="line">            Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)</span><br><span class="line">                    .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;这里如果是远程暴露是时，将会直接进入REGISTRY_PROTOCOL中，进行远程注册。在RegistryProtocol中：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> &lt;T&gt; <span class="function">Exporter&lt;T&gt; <span class="title">export</span><span class="params">(<span class="keyword">final</span> Invoker&lt;T&gt; originInvoker)</span> <span class="keyword">throws</span> RpcException </span>&#123;</span><br><span class="line">    URL registryUrl = getRegistryUrl(originInvoker);</span><br><span class="line">    <span class="comment">// url to export locally</span></span><br><span class="line">    URL providerUrl = getProviderUrl(originInvoker);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Subscribe the override data</span></span><br><span class="line">    <span class="comment">// FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call</span></span><br><span class="line">    <span class="comment">//  the same service. Because the subscribed is cached key with the name of the service, it causes the</span></span><br><span class="line">    <span class="comment">//  subscription information to cover.</span></span><br><span class="line">    <span class="comment">// 订阅override数据</span></span><br><span class="line">    <span class="comment">// FIXME 提供者订阅时，会影响同一JVM即暴露服务，又引用同一服务的的场景，</span></span><br><span class="line">    <span class="comment">// 因为subscribed以服务名为缓存的key，导致订阅信息覆盖。</span></span><br><span class="line">    <span class="keyword">final</span> URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);</span><br><span class="line">    <span class="keyword">final</span> OverrideListener overrideSubscribeListener = <span class="keyword">new</span> OverrideListener(overrideSubscribeUrl, originInvoker);</span><br><span class="line">    overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);</span><br><span class="line"></span><br><span class="line">    providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">//export invoker</span></span><br><span class="line">    <span class="comment">// 在本地暴露服务</span></span><br><span class="line">    <span class="keyword">final</span> ExporterChangeableWrapper&lt;T&gt; exporter = doLocalExport(originInvoker, providerUrl);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// url to registry</span></span><br><span class="line">    <span class="comment">// 拿到zookeeper的注册信息</span></span><br><span class="line">    <span class="keyword">final</span> Registry registry = getRegistry(originInvoker);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取需要暴露provider的url对象，dubbo的注册订阅通信都是以url作为参数传递的</span></span><br><span class="line">    <span class="keyword">final</span> URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl);</span><br><span class="line">    ProviderInvokerWrapper&lt;T&gt; providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker,</span><br><span class="line">            registryUrl, registeredProviderUrl);</span><br><span class="line">    <span class="comment">//to judge if we need to delay publish</span></span><br><span class="line">    <span class="keyword">boolean</span> register = registeredProviderUrl.getParameter(<span class="string">&quot;register&quot;</span>, <span class="keyword">true</span>);</span><br><span class="line">    <span class="keyword">if</span> (register) &#123;</span><br><span class="line">        <span class="comment">// 注册服务</span></span><br><span class="line">        register(registryUrl, registeredProviderUrl);</span><br><span class="line">        providerInvokerWrapper.setReg(<span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Deprecated! Subscribe to override rules in 2.6.x or before.</span></span><br><span class="line">    <span class="comment">// 暴露的同时订阅服务，另外会在zk上创建configurators节点信息</span></span><br><span class="line">    registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);</span><br><span class="line"></span><br><span class="line">    exporter.setRegisterUrl(registeredProviderUrl);</span><br><span class="line">    exporter.setSubscribeUrl(overrideSubscribeUrl);</span><br><span class="line">    <span class="comment">//Ensure that a new exporter instance is returned every time export</span></span><br><span class="line">    <span class="comment">// 保证每次export都返回一个新的exporter实例</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> DestroyableExporter&lt;&gt;(exporter);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 注册服务</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(URL registryUrl, URL registeredProviderUrl)</span> </span>&#123;</span><br><span class="line">    Registry registry = registryFactory.getRegistry(registryUrl);</span><br><span class="line">    registry.register(registeredProviderUrl);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>&emsp;&emsp;这里经过AbstractRegistry，FailbackRegistry，到了ZookeeperRegistry，调用了doRegister方法，在zk上注册节点，注册完成。这里也可以不选择zk，也可以有其他的注册位置。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doRegister</span><span class="params">(URL url)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, <span class="keyword">true</span>));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> RpcException(<span class="string">&quot;Failed to register &quot;</span> + url + <span class="string">&quot; to zookeeper &quot;</span> + getUrl() + <span class="string">&quot;, cause: &quot;</span> + e.getMessage(), e);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="popular-posts-header">相关文章</div><ul class="popular-posts"><li class="popular-posts-item"><div class="popular-posts-title"><a href="\hexoblog\md\rpc\dubbo\dubboSPI扩展机制基本使用，自动包装\" rel="bookmark">dubboSPI扩展机制基本使用，自动包装</a></div></li><li class="popular-posts-item"><div class="popular-posts-title"><a href="\hexoblog\md\rpc\dubbo\dubboSPI扩展机制自适应\" rel="bookmark">dubboSPI扩展机制自适应</a></div></li><li class="popular-posts-item"><div class="popular-posts-title"><a href="\hexoblog\md\rpc\dubbo\dubboSPI扩展点自动激活\" rel="bookmark">dubboSPI扩展点自动激活</a></div></li><li class="popular-posts-item"><div class="popular-posts-title"><a href="\hexoblog\md\rpc\dubbo\dubbo基础及介绍\" rel="bookmark">dubbo基础及介绍</a></div></li><li class="popular-posts-item"><div class="popular-posts-title"><a href="\hexoblog\md\rpc\dubbo\dubbo服务引入流程\" rel="bookmark">dubbo服务引入流程</a></div></li></ul><footer class="post-footer"><div class="post-copyright"><ul><li class="post-copyright-author"><strong>本文作者： </strong>九分石人</li><li class="post-copyright-link"><strong>本文链接：</strong> <a href="https://linqiankun.github.io/hexoblog/md/rpc/dubbo/dubbo%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%9A%B4%E9%9C%B2%E8%BF%87%E7%A8%8B/" title="dubbo服务启动暴露过程">https://linqiankun.github.io/hexoblog/md/rpc/dubbo/dubbo服务启动暴露过程/</a></li><li class="post-copyright-license"><strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh-CN" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！</li></ul></div><div class="followme"><span>欢迎关注我的其它发布渠道</span><div class="social-list"><div class="social-item"><a target="_blank" class="social-link" href="https://github.com/linqiankun"><span class="icon"><i class="fab fa-github"></i> </span><span class="label">GitHub</span></a></div><div class="social-item"><a target="_blank" class="social-link" href="https://gitee.com/linqiankun"><span class="icon"><i class="fab fa-git"></i> </span><span class="label">Gitee</span></a></div><div class="social-item"><a target="_blank" class="social-link" href="/hexoblog/images/thefive.jpg"><span class="icon"><i class="fab fa-weixin"></i> </span><span class="label">WeChat</span></a></div><div class="social-item"><a target="_blank" class="social-link" href="/hexoblog/atom.xml"><span class="icon"><i class="fa fa-rss"></i> </span><span class="label">RSS</span></a></div></div></div><div class="post-tags"><a href="/hexoblog/tags/dubbo/" rel="tag"><i class="fa fa-tag"></i> dubbo</a> <a href="/hexoblog/tags/rpc/" rel="tag"><i class="fa fa-tag"></i> rpc</a></div><div class="post-nav"><div class="post-nav-item"><a href="/hexoblog/md/rpc/dubbo/dubboSPI%E6%89%A9%E5%B1%95%E7%82%B9%E8%87%AA%E5%8A%A8%E6%BF%80%E6%B4%BB/" rel="prev" title="dubboSPI扩展点自动激活"><i class="fa fa-chevron-left"></i> dubboSPI扩展点自动激活</a></div><div class="post-nav-item"><a href="/hexoblog/md/rpc/dubbo/dubbo%E6%9C%8D%E5%8A%A1%E5%BC%95%E5%85%A5%E6%B5%81%E7%A8%8B/" rel="next" title="dubbo服务引入流程">dubbo服务引入流程 <i class="fa fa-chevron-right"></i></a></div></div></footer></article></div><script>window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      const activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      const commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }</script></div></main><footer class="footer"><div class="footer-inner"><div class="copyright">&copy; Tue Mar 02 2021 08:00:00 GMT+0800 (中国标准时间) – <span itemprop="copyrightYear">2025</span> <span class="with-love"><i class="fa fa-heart"></i> </span><span class="author" itemprop="copyrightHolder">九分石人</span></div><div class="wordcount"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="fa fa-chart-line"></i> </span><span title="站点总字数">682k</span> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="fa fa-coffee"></i> </span><span title="站点阅读时长">10:20</span></span></div><div class="busuanzi-count"><span class="post-meta-item" id="busuanzi_container_site_uv" style="display:none"><span class="post-meta-item-icon"><i class="fa fa-user"></i> </span><span class="site-uv" title="总访客量"><span id="busuanzi_value_site_uv"></span> </span></span><span class="post-meta-item" id="busuanzi_container_site_pv" style="display:none"><span class="post-meta-item-icon"><i class="fa fa-eye"></i> </span><span class="site-pv" title="总访问量"><span id="busuanzi_value_site_pv"></span></span></span></div></div></footer><script size="300" alpha="0.6" zindex="-1" src="https://unpkg.com/ribbon.js@1.0.2/dist/ribbon.min.js"></script><script src="https://unpkg.com/animejs@3.2.1/lib/anime.min.js"></script><script src="https://unpkg.com/jquery@3.6.0/dist/jquery.min.js"></script><script src="https://unpkg.com/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script><script src="https://unpkg.com/pangu@4.0.7/dist/browser/pangu.min.js"></script><script src="/hexoblog/js/utils.js"></script><script src="/hexoblog/js/motion.js"></script><script src="/hexoblog/js/next-boot.js"></script><script src="/hexoblog/js/bookmark.js"></script><script src="/hexoblog/js/local-search.js"></script><script>var mermaidElements = document.querySelectorAll('.mermaid');
if (mermaidElements.length) {
  NexT.utils.getScript('https://unpkg.com/mermaid@8.9.2/dist/mermaid.min.js', () => {
    mermaidElements.forEach(element => {
      const newElement = document.createElement('div');
      newElement.innerHTML = element.innerHTML;
      newElement.className = element.className;
      element.parentNode.replaceChild(newElement, element);
    });

    mermaid.init({
      theme    : 'default',
      logLevel : 3,
      flowchart: { curve     : 'linear' },
      gantt    : { axisFormat: '%m/%d/%Y' },
      sequence : { actorMargin: 50 }
    }, '.mermaid');
  }, window.mermaid);
}</script><script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><script src="https://unpkg.com/darkmode-js@1.5.7/lib/darkmode-js.min.js"></script><script>var options = {
  bottom: '64px',
  right: 'unset',
  left: '32px',
  time: '0.5s',
  mixColor: 'transparent',
  backgroundColor: 'transparent',
  buttonColorDark: '#100f2c',
  buttonColorLight: '#fff',
  saveInCookies: true,
  label: '🌓',
  autoMatchOsTheme: true
}
const darkmode = new Darkmode(options);
window.darkmode = darkmode;
darkmode.showWidget();</script></body></html>